using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using Microsoft.SharePoint;
using System.Collections.Generic;
using DE.Sdc.SharePoint.SPContentStructure.Common;

namespace DE.Sdc.SharePoint.SPContentStructure.Import
{
    [Serializable]
    [XmlType(AnonymousType = true, Namespace = DeploymentConstants.Namespace)]
    [XmlRoot(Namespace = DeploymentConstants.Namespace, IsNullable = false)]
    public class Web : Folder, IImportDefinition<SPWeb, SPWeb>
    {
        public Web()
        {
            Webs = new Webs();
            Lists = new Lists();
            Files = new Files();

            
        }

        public new Web Parent
        {
            get
            {
                return (Web)base.Parent;
            }
            set
            {
                base.Parent = value;
            }
        }

        /// <remarks/>
        [XmlAttribute]
        public string Description { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public string Template { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public uint Lcid { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public string Theme { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public string MasterUrl { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public string CustomMasterUrl { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public bool InheritMaster { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public bool InheritCustomMaster { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public bool ParserEnabled { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public bool NoCrawl { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public WebASPXPageIndexMode AspxPageIndexMode { get; set; }

        

        /// <remarks/>
        [XmlElement(typeof(Webs))]
        public Webs Webs { get; set; }

        [XmlIgnore]
        public bool WebsSpecified
        {
            get
            {
                return Webs != null && Webs.Items.Count > 0;
            }
        }

        /// <remarks/>
        [XmlElement(typeof(Lists))]
        public Lists Lists { get; set; }

        [XmlIgnore]
        public bool ListsSpecified
        {
            get
            {
                return Lists != null && Lists.Items.Count > 0;
            }
        }

        [XmlElement(typeof(Files))]
        public Files Files { get; set; }

        [XmlIgnore]
        public bool FilesSpecified
        {
            get
            {
                return Files != null && Files.Items.Count > 0;
            }
        }

        [XmlElement]
        public Navigation Navigation { get; set; }



        [XmlIgnore]
        public new SPWeb UpdatedSPObject { get; internal set; }

        protected override bool IsNewVersion(object sharePointObject)
        {
            if (sharePointObject == null || Version == 0)
                return true;

            SPWeb web = (SPWeb)sharePointObject;
            Trace.WriteLine("Check version number for web " + web.Url, "ContentStructureImporter:ImportWeb");

            if (web.Properties.ContainsKey(DeploymentConstants.ContentStructureVersion))
            {
                int currentVersion = int.Parse(web.Properties[DeploymentConstants.ContentStructureVersion]);
                Trace.WriteLine("Current version is " + currentVersion + ", new version is " + Version + " for web " + web.Url, "ContentStructureImporter:ImportWeb");
                return Version > currentVersion;
            }

            return true;
        }

        protected override void SetNewVersion(object sharePointObject)
        {
            if (sharePointObject == null || Version == 0)
                return;

            SPWeb web = (SPWeb)sharePointObject;
            if (web.Properties.ContainsKey(DeploymentConstants.ContentStructureVersion))
                web.Properties[DeploymentConstants.ContentStructureVersion] = Version.ToString();
            else
                web.Properties.Add(DeploymentConstants.ContentStructureVersion, Version.ToString());
        }

        /// <summary>
        /// Creates a web in a given web
        /// </summary>
        /// <param name="parentWeb">The parent web where to create the web</param>
        /// <returns>The created web</returns>
        private SPWeb CreateWeb(SPWeb parentWeb)
        {
            string webName = DeploymentHelper.Resolve(Title, parentWeb.Locale);
            string webUrl = DeploymentHelper.Resolve(Url, parentWeb.Locale);
            string webDescription = DeploymentHelper.Resolve(Description, parentWeb.Locale);
            string webTemplate = DeploymentHelper.Resolve(Template, parentWeb.Locale);
            Trace.WriteLine("Try to create web '" + Title + "' with url '" + AbsoluteUrl + "'.", "ContentStructureImporter:CreateWeb");

            SPWeb newWeb = parentWeb.Site.AllWebs.Add(AbsoluteUrl, webUrl ?? webName, webDescription, Lcid, webTemplate, false, false);

            newWeb.Update();
            Trace.WriteLine("Web '" + Title + "' with url '" + AbsoluteUrl + "' created.", "ContentStructureImporter:CreateWeb");
            return newWeb;
        }

        /// <summary>
        /// Changes/Updates the properties of the given web
        /// </summary>
        /// <param name="web">A web based on the webDefinition</param>
        private void UpdateWeb(SPWeb web)
        {
            Trace.WriteLine("Try to modify web '" + Title + "' with url '" + AbsoluteUrl + "'.", "ContentStructureImporter:Web.UpdateWeb");

            if (InheritMaster)
                web.MasterUrl = web.ParentWeb != null ? web.ParentWeb.MasterUrl : web.MasterUrl;
            else if (!string.IsNullOrEmpty(MasterUrl))
                web.MasterUrl = DeploymentHelper.Resolve(MasterUrl, web.Locale);

            if (InheritCustomMaster)
                web.CustomMasterUrl = web.ParentWeb != null ? web.ParentWeb.CustomMasterUrl : web.CustomMasterUrl;
            else if (!string.IsNullOrEmpty(CustomMasterUrl))
                web.CustomMasterUrl = DeploymentHelper.Resolve(CustomMasterUrl, web.Locale);

            ModifyProperty("__InheritsMasterUrl", InheritMaster.ToString(), false,
                               web.AllProperties);
            ModifyProperty("__InheritsCustomMasterUrl", InheritCustomMaster.ToString(), false,
                               web.AllProperties);

            web.NoCrawl = NoCrawl;
            web.ASPXPageIndexMode = AspxPageIndexMode;

            if (!string.IsNullOrEmpty(Title))
                web.Title = DeploymentHelper.Resolve(Title, web.Locale);

            web.ParserEnabled = ParserEnabled;
            web.Update();

            if (!string.IsNullOrEmpty(Theme))
            {
                using (SPWeb themeWeb = web.Site.OpenWeb(web.ServerRelativeUrl))
                {
                    themeWeb.AllowUnsafeUpdates = true;
                    themeWeb.ApplyTheme(DeploymentHelper.Resolve(Theme, themeWeb.Locale));
                    themeWeb.Update();
                    themeWeb.AllowUnsafeUpdates = false;
                }
            }

            Trace.WriteLine("Web '" + Title + "' with url '" + AbsoluteUrl + "' modified.", "ContentStructureImporter:Web.UpdateWeb");
        }

        /// <summary>
        /// Deletes a web and all subwebs
        /// </summary>
        /// <param name="web">The web to delete</param>
        private static void DeleteWeb(SPWeb web)
        {
            Trace.WriteLine("Try to delete web '" + web.Title + "' with url '" + web.Url + "'.", "ContentStructureImporter:DeleteWeb");

            SPWebCollection webs = web.Webs;

            if (webs.Count > 0)
            {
                for (int index = 0; index < webs.Count; index++)
                {
                    using (SPWeb innerWeb = webs[index])
                    {
                        DeleteWeb(innerWeb);
                    }
                }
            }

            web.Delete();
            Trace.WriteLine("Web '" + web.Title + "' with url '" + web.Url + "' deleted.", "ContentStructureImporter:DeleteWeb");
        }

        public void ImportDefinition(SPWeb web, SPWeb parentWeb)
        {
            Trace.WriteLine("Try to import web '" + Title + "' with url '" + AbsoluteUrl + "'.", "ContentStructureImporter:Web.ImportDefinition");

            //Set parent for all contained list and webs explicitly!
            foreach (var childList in Lists.Items)
                childList.Parent = this;
            foreach (var childWeb in Webs.Items)
                childWeb.Parent = this;

            if (web == null)
            {
                if (Action == ActionType.AddOrUpdate || Action == ActionType.Replace)
                    web = CreateWeb(parentWeb);
                else
                    return;
            }
            else if (Action == ActionType.Replace && IsNewVersion(web))
            {
                DeleteWeb(web);
                web = CreateWeb(parentWeb);
            }
            else if (Action == ActionType.Delete)
            {
                DeleteWeb(web);
                return;
            }

            SetNewVersion(web);

            DeploymentContext.Current.Web = web;
            DeploymentContext.Current.WebDefinition = this;
            DeploymentContext.Current.CurrentObjectType = DeploymentContext.DeploymentObjects.Web;

            if (Action != ActionType.None &&
                Action <= ActionType.AddOrUpdateOrReplace)
                UpdateWeb(web);

            

            // Import Items
            foreach (Item itemDefinition in Items)
            {
                SPFile file = null;

                itemDefinition.Title = DeploymentHelper.Resolve(itemDefinition.Title, web.Locale);
                itemDefinition.Url = DeploymentHelper.GetRootedUrl(DeploymentHelper.Resolve(itemDefinition.Url, web.Locale), web.ServerRelativeUrl);

                try
                {
                    file = web.GetFile(itemDefinition.Url ?? "/" + itemDefinition.Title);
                }
                catch (FileNotFoundException) { }
                catch (ArgumentNullException) { }
                catch (ArgumentException) { }

                DeploymentContext.Current.File = file;
                DeploymentContext.Current.FileDefinition = itemDefinition.File;
                itemDefinition.File.ImportDefinition(file, web.RootFolder);
            }

            Lists.ImportDefinition(web, web);

            DeploymentContext.Current.List = null;
            DeploymentContext.Current.CurrentObjectType = DeploymentContext.DeploymentObjects.Web;
            //Import Webs
            Webs.ImportDefinition(web, web);

            if (Navigation != null)
            {
                using (SPSite navigationSite = new SPSite(web.Site.ID))
                {
                    using (SPWeb navigationWeb = navigationSite.OpenWeb(web.ID))
                    {
                        Navigation.ModifyNavigation(Navigation, navigationWeb.Navigation);
                        DeploymentContext.Current.CurrentObjectType = DeploymentContext.DeploymentObjects.Navigation;
                    }
                }
            }
            DeploymentContext.Current.CurrentObjectType = DeploymentContext.DeploymentObjects.Web;

            

            web.Dispose();

            Trace.WriteLine("Web '" + Title + "' with url '" + AbsoluteUrl + "' imported.", "ContentStructureImporter:ImportWeb");
            UpdatedSPObject = web;
        }   
    }
}